package com.audaque.springboot.foshanupload.security.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.audaque.springboot.foshanupload.authcore.model.currentUser.TransmittableThreadLocalCurrentUser;
import com.audaque.springboot.foshanupload.security.encoder.MyPasswordEncoder;
import com.audaque.springboot.foshanupload.security.model.MyGrantedAuthority;
import com.audaque.springboot.foshanupload.security.model.MyUserDetail;
import com.audaque.springboot.foshanupload.security.properties.UserDetailServiceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * @author zgb
 * @desc 作为数据库代理
 * @date 2022-08-05 17:35:30
 */
@Service
public class MyUserDetailService implements UserDetailsService, ApplicationContextAware {
    @Autowired
    private MyPasswordEncoder myPasswordEncoder;
    @Autowired
    private UserDetailServiceProperties userDetailServiceProperties;

    @Value("${db.tenantId}")
    private String tenantId;

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        MyUserDetailService.applicationContext = applicationContext;
    }

    /**
     * 根据用户名生成认证令牌：UsernamePasswordAuthenticationToken(myUserDetail, password,
     * authorities);
     *
     * @param username
     * @return
     */
    public UsernamePasswordAuthenticationToken getUsernamePasswordAuthenticationTokenByByUsername(String username) {
        // 数据库里
        MyUserDetail myUserDetail = (MyUserDetail) this.loadUserByUsername(username);

        if (myUserDetail == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }

        String password = myUserDetail.getPassword();
        Set<MyGrantedAuthority> authorities = myUserDetail.getAuthorities();
        // myUserDetail作为身份信息
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                myUserDetail, password, authorities);
        return usernamePasswordAuthenticationToken;

    }

    /**
     * 根据用户名查用户信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Object userService = applicationContext.getBean(userDetailServiceProperties.getLoadUserByUsernameBean());
        Method loadUserByUsername = null;
        try {
            loadUserByUsername = userService.getClass().getMethod(userDetailServiceProperties.getLoadUserByUsernameMethod(), String.class);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        Object map = null;
        try {
            map = loadUserByUsername.invoke(userService, username);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        if (map == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        MyUserDetail myUserDetail = BeanUtil.toBean(map, MyUserDetail.class);
        if (!myUserDetail.getEnableYn()) {
            throw new DisabledException("用户名已被禁用");
        }

        myUserDetail.setAccountNonExpired(true).setAccountNonLocked(true).setCredentialsNonExpired(true)
                .setEnabled(true);
        return myUserDetail;

    }

    public boolean permissionMatch(String permission) {
        TransmittableThreadLocalCurrentUser transmittableThreadLocalCurrentUser = TransmittableThreadLocalCurrentUser.getCurrentUser();
        Set<String> roleIds = transmittableThreadLocalCurrentUser.getRoleIds();
        for (String roleId : roleIds) {
            if (permission.matches(roleId)) {
                return true;
            }
        }
        return false;
    }
}
